package com.com.wdy.invocation;

import java.util.Optional;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @ClassName: ThreadSyncExector
 * @Description: TODO
 * @Date: 2019/12/30 17:56
 * @Author: wangdy001
 * @Version: 1.0
 */
public class ThreadSyncExector<T> {
    private AtomicInteger idx = new AtomicInteger(1);

    public AsyncResult<T> startProcess(Callable<T> callable, AsyncCallback<T> asyncCallback) {
        CompletableResult<T> result = new CompletableResult<>(asyncCallback);
        new Thread(() -> {
            try {
                result.setValue(callable.call());
            } catch (Exception e) {
                result.setException(e);
            }
        }).start();
        return result;
    }

    public AsyncResult<T> startProcess(Callable<T> callable) {
        return startProcess(callable, null);
    }

    private static class CompletableResult<T> implements AsyncResult<T> {
        private final int RUNNING = 1;
        private final int FAIL = 2;
        private final int COMPLETED = 3;
        private volatile int state = RUNNING;

        private T value;
        private Exception exception;

        private Object lock;
        private Optional<AsyncCallback<T>> callback;

        public CompletableResult() {
            this.lock = new Object();
        }

        public CompletableResult(AsyncCallback<T> callback) {
            this();
            this.callback = Optional.ofNullable(callback);
        }

        void setValue(T value){
            this.value = value;
            this.state = COMPLETED;
            this.callback.ifPresent(ca->ca.onComplete(value, Optional.empty()));
            synchronized (lock) {
                lock.notifyAll();
            }
        }

        void setException(Exception ex){
            this.exception = ex;
            this.state = FAIL;
            this.callback.ifPresent(ca->ca.onComplete(null, Optional.of(ex)));
            synchronized (lock) {
                lock.notifyAll();
            }
        }

        @Override
        public T getValue() {
            return value;
        }

        @Override
        public boolean isComplete() {
           return state > RUNNING;
        }

        @Override
        public void await() throws InterruptedException {
            synchronized (lock) {
                while(!isComplete()) {
                    lock.wait();
                }
            }
        }
    }
}
